package raft

import "fmt"

//
// example RequestVote RPC handler.
//
func (rf *Raft) RequestVote(args *RequestVoteArgs, reply *RequestVoteReply) {
	rf.mu.Lock()
	defer rf.mu.Unlock()
	reply.Term = rf.currentTerm

	rf.Fprint(fmt.Sprintf("-----------------RequestVote-----------------\n args is : \n%v\n. rf.log is : \n %v\n", args, rf.log))

	if args.Term < rf.currentTerm || args.Term == rf.currentTerm && rf.votedFor != -1 && rf.votedFor != args.CandidateId {
		reply.VoteGranted = false
		return
	}

	rf.currentTerm = args.Term
	rf.status = Follow

	// 如果 本地log最后一项的任期大于参数的任期
	// 或者 本地log最后一项的任期等于参数的任期 且 本地的日志比参数的日志要长
	// 则不投票给他
	if rf.log[len(rf.log)-1].Term > args.LastLogTerm || rf.log[len(rf.log)-1].Term == args.LastLogTerm && len(rf.log) > args.LastLogIndex+1 {
		reply.VoteGranted = false
		return
	}

	// 两个 receive的这里必须要启动 go协程去处理，否则reqCh阻塞会导致死锁
	go func() {
		rf.reqCh <- 1
	}()
	rf.votedFor = args.CandidateId
	reply.VoteGranted = true

	return
}

func (rf *Raft) AppendEntries(args *AppendEntriesArgs, reply *AppendEntriesReply) {
	rf.mu.Lock()
	defer rf.mu.Unlock()
	reply.Term = rf.currentTerm
	if args.Term < rf.currentTerm {
		reply.Success = false
		return
	}
	prevLogIndex := args.PrevLogIndex
	prevLogTerm := args.PrevLogTerm

	// 如果 Leader已经提交的日志要新于本机，或者有冲突，减少 nextIndex重发
	if prevLogIndex >= len(rf.log) || rf.log[prevLogIndex].Term != prevLogTerm {
		reply.Success = false
		return
	}

	rf.log = append(rf.log[:prevLogIndex+1], args.Entries...)

	if args.LeaderCommit > rf.commitIndex {
		rf.updateCommitIndex(GetMin(args.LeaderCommit, len(rf.log)-1))
	}

	rf.Fprint(fmt.Sprintf("-----------------AppendEntries-----------------\nmy log is: %v\n", rf.log))
	rf.status = Follow

	go func() {
		rf.reqCh <- 1
	}()
	rf.currentTerm = args.Term
	reply.Success = true
	rf.votedFor = -1
	return
}
